﻿using System;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// 类型转换基类
    /// </summary>
    public abstract class TypeConverterAbs : ITypeConverter
    {

        /// <summary>
        /// 转换器类型
        /// </summary>

        protected readonly Type _converterType;

        /// <summary>
        /// 类型编码
        /// </summary>
        protected readonly TypeCode _code;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="converterType">转换器类型</param>
        public TypeConverterAbs(Type converterType)
        {
            this._converterType = converterType;
            this._code = Type.GetTypeCode(converterType);
        }



        /// <summary>
        /// 转换器类型
        /// </summary>
        public Type ConverterType
        {
            get { return _converterType; }
        }



        /// <summary>
        /// 转换数据到
        /// </summary>
        /// <param name="targetValueType">要待转换的目标类型</param>
        /// <param name="value">要转换的值</param>
        /// <param name="result">转换后的值,存放在object中,如果转换失败为目标类型的默认值</param>
        /// <returns>转换成功返回true,失败返回false</returns>
        public bool TryConvertTo(Type targetValueType, object value, out object result)
        {
            return this.PrimitiveTryConvertTo(targetValueType, value, out result);
        }

        /// <summary>
        /// 转换数据到
        /// </summary>
        /// <param name="targetValueType">要待转换的目标类型</param>
        /// <param name="value">要转换的值</param>
        /// <param name="result">转换后的值,存放在object中,如果转换失败为目标类型的默认值</param>
        /// <returns>转换成功返回true,失败返回false</returns>
        protected virtual bool PrimitiveTryConvertTo(Type targetValueType, object value, out object result)
        {
            try
            {
                if (value != null && value.GetType() == targetValueType)
                {
                    result = value;
                }
                else
                {
                    result = Convert.ChangeType(value, targetValueType);
                }
                return true;
            }
            catch (Exception ex)
            {
                ZLog.ZLoger.Warn(ex);
                result = null;
                return false;
            }
        }




        /// <summary>
        /// 将字符串转换为值类型数据,包括枚举
        /// </summary>
        /// <param name="targetType">要待转换的目标类型</param>
        /// <param name="value">要转换的值</param>
        /// <param name="fromBase">值中数字基数(value是何种进制的字符串),必须是2,8,10,16</param>
        /// <returns>转换后的值</returns>
        public object ConvertTo(Type targetType, string value, byte fromBase)
        {
            return this.PrimitiveConvertTo(targetType, value, fromBase);
        }

        /// <summary>
        /// 将字符串转换为值类型数据,包括枚举
        /// </summary>
        /// <param name="targetType">要待转换的目标类型</param>
        /// <param name="value">要转换的值</param>
        /// <param name="fromBase">值中数字基数(value是何种进制的字符串),必须是2,8,10,16</param>
        /// <returns>转换后的值</returns>
        protected virtual object PrimitiveConvertTo(Type targetType, string value, byte fromBase = 10)
        {
            throw new NotSupportedException($"目标类型\"{targetType.FullName}\"不支持进制格式转换");
        }






        /// <summary>
        /// 尝试将字符串转换为值类型数据,包括枚举
        /// </summary>
        /// <param name="targetType">要待转换的目标类型</param>
        /// <param name="value">要转换的值</param>
        /// <param name="result">转换结果</param>
        /// <param name="style">字符串中数值样式[数字样式为NumberStyles值之一，日期时间为DateTimeStyles值之一,默认null为不使用样式]</param>
        /// <param name="formatProvider">一个提供区域性特定的格式设置信息的对象</param>
        /// <returns>转换成功返回true,失败返回false</returns>
        public bool TryConvertTo(Type targetType, string value, out object result, object style = null, IFormatProvider formatProvider = null)
        {
            return this.PrimitiveTryConvertTo(targetType, value, out result, style, formatProvider);
        }

        /// <summary>
        /// 尝试将字符串转换为值类型数据,包括枚举
        /// </summary>
        /// <param name="targetType">要待转换的目标类型</param>
        /// <param name="value">要转换的值</param>
        /// <param name="result">转换结果</param>
        /// <param name="style">字符串中数值样式[数字样式为NumberStyles值之一，日期时间为DateTimeStyles值之一,默认null为不使用样式]</param>
        /// <param name="formatProvider">一个提供区域性特定的格式设置信息的对象</param>
        /// <returns>转换成功返回true,失败返回false</returns>
        protected abstract bool PrimitiveTryConvertTo(Type targetType, string value, out object result, object style = null, IFormatProvider formatProvider = null);




#if CORE
        /// <summary>
        /// 尝试将字符串转换为值类型数据,包括枚举
        /// </summary>
        /// <param name="targetType">要待转换的目标类型</param>
        /// <param name="value">要转换的值</param>
        /// <param name="result">转换结果</param>
        /// <param name="style">字符串中数值样式[数字样式为NumberStyles值之一，日期时间为DateTimeStyles值之一,默认null为不使用样式]</param>
        /// <param name="formatProvider">一个提供区域性特定的格式设置信息的对象</param>
        /// <returns>转换成功返回true,失败返回false</returns>
        public bool TryConvertTo(Type targetType, ReadOnlySpan<char> value, out object result, object style = null, IFormatProvider formatProvider = null)
        {
            return this.PrimitiveTryConvertTo(targetType, value, out result, style, formatProvider);
        }

        /// <summary>
        /// 尝试将字符串转换为值类型数据,包括枚举
        /// </summary>
        /// <param name="targetType">要待转换的目标类型</param>
        /// <param name="value">要转换的值</param>
        /// <param name="result">转换结果</param>
        /// <param name="style">字符串中数值样式[数字样式为NumberStyles值之一，日期时间为DateTimeStyles值之一,默认null为不使用样式]</param>
        /// <param name="formatProvider">一个提供区域性特定的格式设置信息的对象</param>
        /// <returns>转换成功返回true,失败返回false</returns>
        protected abstract bool PrimitiveTryConvertTo(Type targetType, ReadOnlySpan<char> value, out object result, object style = null, IFormatProvider formatProvider = null);
#endif

    }
}
